import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_common/flutter_common.dart';
import 'package:flutter_common/util/string_utils.dart';

///从底部弹出的弹窗，默认列表样式，可以通过child、builder完全自定义弹窗内容
///
///名称showBottomSheet与package:flutter/src/material/bottom_sheet.dart中的名称冲突
Future<R?> showSelectBottomSheet<T, U, R>(
    BuildContext context, {
      WidgetBuilder? builder,
      Widget? child,
      bool isDismissible = true,
      bool useRootNavigator = false,
      bool useSafeArea = false,
      Color? color = Colors.white,
      Function()? onCancelPress,
      Function(List<T>)? onOkPress,
      String? title,
      Widget? titleWidget,
      bool multi = false,
      List<T>? list,
      List<U>? selectList, //不为空，或者equals不为空 则多选
      ///将[T]转换成字符串 显示在列表上
      ValueMapper<T, String>? optionMapper,
      Equals<U, T>? equals,
      ///将选中的结果，转换成[R]，并返回
      ValueMapper<List<T>, R>? selectedMapper,
    }) {
  // showBottomSheet 有限制最大高度 为屏幕高一半
  return showDialog<R>(
    useRootNavigator: useRootNavigator,
    useSafeArea: useSafeArea,
    context: context,
    routeSettings: const RouteSettings(name: "bottom_sheet"),
    barrierDismissible: isDismissible,
    builder: (context) {
      return FxSelectListDialog<T, U, R>(
        outsideCancel: isDismissible,
        title: title,
        titleWidget: titleWidget,
        color: color,
        multi: multi,
        onCancelPress: onCancelPress,
        onOkPress: onOkPress,
        list: list,
        selectList: selectList,
        optionMapper: optionMapper,
        equals: equals,
        selectedMapper: selectedMapper,
        child: child ?? builder?.call(context),
      );
    },
  );
}



/// 输入的值转为另外一个输出的值
/// [t] 输入的值
/// [R] 输出的值
typedef ValueMapper<T, R> = R Function(T t);

/// 比较两个值是否相同
typedef Equals<A, B> = bool Function(A a, B b);

///选择列表弹窗，默认显示在底部的弹窗  T所有选项数据类型，U选中数据类型，R返回数据类型
class FxSelectListDialog<T, U, R> extends StatefulWidget {
  final AlignmentGeometry alignment;
  final bool outsideCancel;
  final BorderRadiusGeometry? borderRadius;
  final BoxConstraints? constraints;
  final double? width;
  final double? height;
  final Color? color;

  //自定义内容
  final Widget? child;

  //取消按钮，没确认按钮，则显示在内容底部
  final Function()? onCancelPress;

  //确认按钮点击，不为空，则跟取消按钮一样显示在内容顶部上方
  final Function(List<T>)? onOkPress;

  //数据，及转化为显示内容
  final String? title;
  final Widget? titleWidget;
  final bool multi;
  final List<T>? list;
  final List<U>? selectList;
  final ValueMapper<T, String>? optionMapper;
  final Equals<U, T>? equals;
  final ValueMapper<List<T>, R>? selectedMapper;

  const FxSelectListDialog({
    Key? key,
    this.alignment = Alignment.bottomCenter,
    this.outsideCancel = true,
    this.borderRadius = const BorderRadius.vertical(top: Radius.circular(10)),
    this.constraints,
    this.width = double.infinity,
    this.height,
    this.color = Colors.white,
    this.child,
    this.title,
    this.titleWidget,
    this.multi = false,
    this.onCancelPress,
    this.onOkPress,
    this.list,
    this.selectList,
    this.optionMapper,
    this.equals,
    this.selectedMapper,
  }) : super(key: key);

  @override
  State<StatefulWidget> createState() => FxSelectListDialogState<T, U, R>();
}

class FxSelectListDialogState<T, U, R>
    extends State<FxSelectListDialog<T, U, R>> {
  final Map<int, T> _selectMap = {};

  @override
  void initState() {
    super.initState();
    _updateSelect();
  }

  @override
  void didUpdateWidget(covariant FxSelectListDialog<T, U, R> oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.list != widget.list ||
        oldWidget.selectList != widget.selectList) {
      _selectMap.clear();
      _updateSelect();
      if (mounted) setState(() {});
    }
  }

  @override
  Widget build(BuildContext context) {
    //包裹背景的方法
    Widget bodyFunc(Widget body) {
      return FxBackgroundDialog(
        alignment: widget.alignment,
        outsideCancel: widget.outsideCancel,
        borderRadius: widget.borderRadius,
        constraints: widget.constraints,
        width: widget.width,
        height: widget.height,
        color: widget.color,
        child: body,
      );
    }

    if (widget.child != null) {
      return bodyFunc(widget.child!);
    }
    List<Widget> list = [];
    if (widget.multi) {
      //多选的 取消、标题、内容
      list.add(multiSelectTopWidget());
    }
    if(widget.titleWidget != null) {
      list.add(widget.titleWidget!);
    }
    final before = beforeListWidget();
    if (before != null) {
      list.add(before);
    }
    //列表内容
    if (widget.height == double.infinity) {
      list.add(Expanded(child: listWidget()));
    } else {
      list.add(Flexible(child: listWidget()));
    }
    //列表之后内容
    final after = afterListWidget();
    if (after != null) {
      list.add(after);
    }
    if (!widget.multi) {
      //单选的取消按钮
      final line = Container(
        height: 4,
        color: Colors.grey[100],
      );
      list.add(line);
      //底部取消按钮
      list.add(singleSelectBottomWidget());
    }
    final body = SafeArea(
      top: widget.height == double.infinity,
      child: Column(mainAxisSize: MainAxisSize.min, children: list),
    );
    //背景
    return bodyFunc(body);
  }

  ///添加其他不同的组件
  Widget? beforeListWidget() => null;

  Widget? afterListWidget() => null;

  ///多选的 取消+标题+确认
  Widget multiSelectTopWidget() {
    //多选 顶部取消按钮、确认按钮
    final child =
    _text(widget.title ?? '', fontSize: 18, color: FxTheme().textColor);
    final top = Row(
      children: [
        _click(child: _text("取消"), onTap: onCancelPress),
        Expanded(child: child),
        _click(
            child: _text("确认", color: FxTheme().buttonColor), onTap: onOkPress),
      ],
    );
    return top;
  }

  ///单选的取消按钮
  Widget singleSelectBottomWidget() {
    return _click(
      onTap: onCancelPress,
      child: Center(
        child: Padding(
          padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 30),
          child: _text("取消"),
        ),
      ),
    );
  }

  Widget _click({Widget? child, Function()? onTap}) {
    return Material(
      //防止外部有颜色 导致没有水波纹
      color: widget.color ?? Colors.white,
      child: InkWell(
        onTap: onTap,
        child: child,
      ),
    );
  }

  Widget _text(String data, {Color? color, double? fontSize}) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 15),
      child: Text(
        data,
        textAlign: TextAlign.center,
        softWrap: true,
        style: TextStyle(
            fontSize: fontSize ?? 14, color: color ?? FxTheme().textColor),
      ),
    );
  }

  Widget listWidget() {
    return ListView.builder(
      shrinkWrap: true,
      itemCount: widget.list?.length ?? 0,
      itemBuilder: (con, index) {
        final T item = widget.list![index];
        final name = widget.optionMapper?.call(item) ?? "$item";
        final selected = _selectMap.containsKey(index);
        return FxSelectOptionWidget(
          name,
          onTap: () => onItemPress(index, item),
          selected: selected,
          color: widget.color,
        );
      },
    );
  }

  ///更新选中事项
  void _updateSelect() {
    final List<T>? first = widget.list;
    final List<U>? select = widget.selectList;
    if (first != null && select != null && select.isNotEmpty) {
      int index = 0;
      for (T item in first) {
        for (U s in select) {
          if (widget.equals?.call(s, item) ?? (s == item)) {
            if (!widget.multi) {
              _selectMap.clear();
            }
            _selectMap[index] = item;
            break;
          }
        }
        index++;
      }
    }
  }

  void onCancelPress() {
    widget.onCancelPress?.call();
    Navigator.pop(context);
  }

  void onOkPress() {
    dynamic res;
    final List<T> list = List<T>.from(_selectMap.values.toList());
    if (widget.selectedMapper != null) {
      res = widget.selectedMapper!.call(list);
    } else {
      res = list;
    }
    widget.onOkPress?.call(res);
    Navigator.pop(context, res);
  }

  void onItemPress(int index, T item) {
    if (!widget.multi) {
      _selectMap.clear();
      //单选
      _selectMap[index] = item;
      if (mounted) setState(() {});
      Future.delayed(const Duration(milliseconds: 200), onOkPress);
      return;
    }
    if (_selectMap.containsKey(index)) {
      _selectMap.remove(index);
    } else {
      _selectMap[index] = item;
    }
    if (mounted) setState(() {});
  }
}

///选择列表的单个选项widget
class FxSelectOptionWidget extends StatelessWidget {
  final String name;
  final VoidCallback onTap;
  final bool selected;
  final Color? color;

  const FxSelectOptionWidget(this.name,
      {Key? key,
        required this.onTap,
        this.selected = false,
        this.color = Colors.white})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Material(
      //防止外部有颜色 导致没有水波纹
      color: color ?? Colors.white,
      child: InkWell(
        onTap: onTap,
        child: Container(
          alignment: Alignment.center,
          padding: const EdgeInsets.symmetric(vertical: 15, horizontal: 8),
          child: Text(
            name,
            softWrap: true,
            style: TextStyle(
              color: selected ? FxTheme().buttonColor : FxTheme().textColor,
            ),
          ),
        ),
      ),
    );
  }
}

class FxBackgroundDialog extends StatelessWidget {
  //弹窗内容，在屏幕中的位置
  final AlignmentGeometry alignment;

  //点击遮罩层，是否能关闭弹窗 true则关闭
  final bool outsideCancel;

  //内容的圆角，默认顶部圆角
  final BorderRadiusGeometry? borderRadius;

  //限制内容宽高
  final BoxConstraints? constraints;

  //内容宽度，默认占满屏幕宽度
  final double? width;

  //内容高度，默认空
  final double? height;

  //内容 背景颜色
  final Color? color;

  //自定义内容
  final Widget? child;

  // final animator = ValueNotifier<double>(0);

  const FxBackgroundDialog({
    Key? key,
    this.alignment = Alignment.bottomCenter,
    this.outsideCancel = true,
    this.borderRadius = const BorderRadius.vertical(top: Radius.circular(10)),
    this.constraints,
    this.width = double.infinity,
    this.height,
    this.color = Colors.white,
    this.child,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    Widget body = Material(
      color: Colors.transparent, //本身不透明的灰白色，改为透明
      child: Container(
        height: double.infinity,
        width: double.infinity,
        alignment: alignment,
        child: ClipRRect(
          borderRadius: borderRadius,
          child: Container(
            width: width,
            height: height,
            color: color,
            constraints: constraints ?? getConstraints(context),
            child: child,
          ),
        ),
      ),
    );
    //允许点击内容外的遮罩层，关闭弹窗
    if (outsideCancel) {
      body = GestureDetector(onTap: () => Navigator.pop(context), child: body);
    }
    //允许返回键关闭弹窗
    body = WillPopScope(child: body, onWillPop: () => Future.value(true));
    return body;
  }

  getConstraints(BuildContext context) {
    if (constraints != null) {
      return constraints!;
    }
    final s = MediaQuery.of(context).size;
    //宽度限制，一般是pad，占据1/3
    final w = width == null ? max(s.width * 1 / 3, min(200.0, s.width)) : min(width!, s.width);
    //高度限制，一般是phone，占据3/4
    final h = height == null ? max(s.height * 4 / 5, min(300.0, s.height)) : min(height!, s.height);
    return BoxConstraints(maxWidth: w, maxHeight: h);
  }
}